#include <casgidriver/CASgiDriverE.h>

// ***********************************************************************

// class EDROOMTopContext

// ***********************************************************************



// CONSTRUCTORES***********************************************

CASgiDriver::EDROOMTopContext::EDROOMTopContext (CASgiDriver &act, uint16_t & EDROOMpVarVByteNumber, bool_t & EDROOMpVarVMessageCompleted, byte_t * EDROOMpVarVStringDataBurst, CEDROOMPOOLCDBurst & EDROOMpPoolCDBurst, CEDROOMPOOLCDDataBurst & EDROOMpPoolCDDataBurst ):

EDROOMcomponent(act)
,Msg(EDROOMcomponent.Msg)
,MsgBack(EDROOMcomponent.MsgBack)
,SGIGround(EDROOMcomponent.SGIGround)
, VByteNumber ( EDROOMpVarVByteNumber )
, VMessageCompleted ( EDROOMpVarVMessageCompleted )
, VStringDataBurst ( EDROOMpVarVStringDataBurst )
, EDROOMPoolCDBurst ( EDROOMpPoolCDBurst )
, EDROOMPoolCDDataBurst ( EDROOMpPoolCDDataBurst )
{

}

CASgiDriver::EDROOMTopContext::EDROOMTopContext ( EDROOMTopContext &contex ):

			EDROOMcomponent(contex.EDROOMcomponent),
			Msg(contex.Msg),
			MsgBack(contex.MsgBack)
,SGIGround(contex.SGIGround)
, VByteNumber ( contex.VByteNumber )
, VMessageCompleted ( contex.VMessageCompleted )
, VStringDataBurst ( contex.VStringDataBurst )
, EDROOMPoolCDBurst ( contex.EDROOMPoolCDBurst )
, EDROOMPoolCDDataBurst ( contex.EDROOMPoolCDDataBurst )
{

}

// EDROOMSearchContextTrans********************************************

bool CASgiDriver::EDROOMTopContext::EDROOMSearchContextTrans(TEDROOMTransId &edroomCurrentTrans){

	bool edroomValidMsg=false; 

	switch(Msg->signal){

		case ( EDROOMSignalDestroy ):

					 edroomValidMsg=true;
		edroomCurrentTrans.distanceToContext = 0 ;
		edroomCurrentTrans.localId = -1 ;
		break;

	}

	return(edroomValidMsg);

}

// Funciones Definidas por el usuario  ****************************

void	CASgiDriver::EDROOMTopContext::FBuildUpBurst()

{
	byte_t codeOfBurst;
	uint8_t i;
	VMessageCompleted=false;
	codeOfBurst = sgi_link_layer_get_code(VStringDataBurst);

	if ((MASK_BURST_A_SGI==codeOfBurst)	|| //DataBurst
			(MASK_BURST_D_SGI==codeOfBurst) ||
			(MASK_BURST_C_SGI==codeOfBurst))
	{
		CDDataBurst * ap_CDDataBurst = EDROOMPoolCDDataBurst.AllocData();
		// Complete Data
		for (i=0;i<32;i++)
		{
			ap_CDDataBurst->header[i]=VStringDataBurst[i];
		}

		/**
		 * TODO: Aquí se deben opiar el resto de datos, en funión de nf
		 */

		// reply
		Msg->reply(SRxDataBurst, ap_CDDataBurst, &EDROOMPoolCDDataBurst);
	}
	else if ((MASK_BURST_F_SGI==codeOfBurst) || //Burst
			(MASK_BURST_B_SGI==codeOfBurst)  ||
			(MASK_BURST_E_SGI==codeOfBurst))
	{
		CDBurst * ap_CDBurst = EDROOMPoolCDBurst.AllocData();
		// Complete Data
		for (i=0;i<32;i++)
		{
			ap_CDBurst->header[i]=VStringDataBurst[i];
		}
		// reply
		Msg->reply(SRxBurst, ap_CDBurst, &EDROOMPoolCDBurst);
	}
	else
	{
		//ERROR
	}

}



void	CASgiDriver::EDROOMTopContext::FCheckBytesReceived()

{

	int8_t offSet;
	byte_t codeOfBurst;

	if ((VByteNumber==32) ||
			(VByteNumber==BUFFER_IRQ_SIZE)) //TODO: esto siempre y cuando la r?faga sea de tama?o fijo lleve o no lleve las 32 tramas
	{
		if (sgi_link_layer_check_crcs(VStringDataBurst,&offSet))
		{

			codeOfBurst = sgi_link_layer_get_code(VStringDataBurst);

			if ((MASK_BURST_A_SGI==codeOfBurst)	|| //DataBurst
					(MASK_BURST_D_SGI==codeOfBurst) ||
					(MASK_BURST_C_SGI==codeOfBurst))
			{
				if (VByteNumber==BUFFER_IRQ_SIZE)
				{
					VByteNumber=0;
					VMessageCompleted=true;
				}
			}
			else if ((MASK_BURST_F_SGI==codeOfBurst) || //Burst
					(MASK_BURST_B_SGI==codeOfBurst)  ||
					(MASK_BURST_E_SGI==codeOfBurst))
			{

				VByteNumber=0;
				VMessageCompleted=true;
			}
			else
			{
				VByteNumber=0;
				//TODO:¿algo más necesario?
			}
		}
		else
		{
			VByteNumber=0;
			//TODO:¿algo más necesario?
		}
	}

}



void	CASgiDriver::EDROOMTopContext::FGetData()

{
	while (VBytesWritten && !(VMessageCompleted))
	{
		VStringDataBurst[VByteNumber]=VBufferIRQ[VReadIndex];
		VReadIndex++;
		VReadIndex%=BUFFER_IRQ_SIZE;//TODO: definir BUFFER_IRQ_SIZE como parametro del config o similar

		VByteNumber++;

		Pr_IRQManager::DisableIRQ(2);
		VBytesWritten--;
		Pr_IRQManager::EnableIRQ(2);
		printf("\n%d\n",VByteNumber);
		FCheckBytesReceived();
	}
}



void	CASgiDriver::EDROOMTopContext::FInit()


{
	//Install IRQ Handler
	Pr_IRQManager::InstallIRQHandler(FReadByteHandler,0,0x12);//TODO: registrar con el SO

	/**
	 * TODO: aqu� inicializar el dispositivo SPI con las funciones del firmware
	 *
	 */
}



void	CASgiDriver::EDROOMTopContext::FNotAnswer()

{

	Msg->reply(SNoAnswer);

}



void	CASgiDriver::EDROOMTopContext::FSendDataBurstToGround()



{
	uint16_t i=0;
	byte_t stringDataBurst[BUFFER_IRQ_SIZE];
	CDDataBurst & varCDDataBurst = *(CDDataBurst *)Msg->data;
	uint8_t nf = sgi_link_layer_get_nf(varCDDataBurst.header);
	uint16_t numberOfBytes=32+nf*256;

	//Copy Header...
	for (i=0; i<32; i++)//cambiar por strncpy
	{
		stringDataBurst[i]=varCDDataBurst.header[i];
	}

	//...and now DataFrames
	PacketsToBytes(varCDDataBurst.packList,stringDataBurst,nf);

	//Send to Modem
	for (i=0;i<numberOfBytes;i++)
	{
		sgi_uart_dev_putchar(stringDataBurst[i]);
	}

	FWaitToResponse();


}



void	CASgiDriver::EDROOMTopContext::FSendBurstToGround()


{

	CDBurst & varCDBurst = *(CDBurst *)Msg->data;
	uint8_t i=0;

	//Send to UART (SPI)
	for (i=0;i<32;i++)
	{
		sgi_uart_dev_putchar(varCDBurst.header[i]);
	}
	FWaitToResponse();

}



void	CASgiDriver::EDROOMTopContext::FWaitToResponse()



{
	uint16_t timeOfWaiting=0;
	float tRxTx= 0.5;//TODO: definir un tiempo m�ximo de espera para considerar que no hay
	//respueta

	Pr_Time	interval(tRxTx); // Declare time var with an initial value in seconds
	printf("\nVMessageCompleted %d\n",VMessageCompleted);
	printf("\ntimeOfWaiting %d\n",timeOfWaiting);
	while (!(VMessageCompleted) && (timeOfWaiting <20))//TODO: O método similar que compare el paso del tiempo en el sistema
	{
		printf("\n %d\n",VMessageCompleted);
		printf("\n %d\n",timeOfWaiting);
		Pr_DelayIn(interval);
		timeOfWaiting++;
		FGetData();
	}


}





//*****Pools

//CEDROOMPOOLCDBurst

CASgiDriver::EDROOMTopContext::CEDROOMPOOLCDBurst::CEDROOMPOOLCDBurst(unsigned int elemCount, CDBurst* pMem, TEDROOMBool * pMemMarks):CEDROOMProtectedMemoryPool(elemCount, pMem, pMemMarks, sizeof (CDBurst)){;}

CDBurst *	CASgiDriver::EDROOMTopContext::CEDROOMPOOLCDBurst::AllocData(){
	return(CDBurst*)CEDROOMProtectedMemoryPool::AllocData();
}

//CEDROOMPOOLCDDataBurst

CASgiDriver::EDROOMTopContext::CEDROOMPOOLCDDataBurst::CEDROOMPOOLCDDataBurst(unsigned int elemCount, CDDataBurst* pMem, TEDROOMBool * pMemMarks):CEDROOMProtectedMemoryPool(elemCount, pMem, pMemMarks, sizeof (CDDataBurst)){;}

CDDataBurst *	CASgiDriver::EDROOMTopContext::CEDROOMPOOLCDDataBurst::AllocData(){
	return(CDDataBurst*)CEDROOMProtectedMemoryPool::AllocData();
}



// ***********************************************************************

// class EDROOMTopState

// ***********************************************************************



// CONSTRUCTOR*************************************************

CASgiDriver::EDROOMTopState::EDROOMTopState (CASgiDriver &act, CEDROOMMemory *pEDROOMMemory  ):
			  EDROOMTopContext( act , VByteNumber, VMessageCompleted, VStringDataBurst,EDROOMPoolCDBurst,EDROOMPoolCDDataBurst )
, VByteNumber ( 0 )
, VMessageCompleted ( false )
, EDROOMPoolCDBurst ( 10, pEDROOMMemory->poolCDBurst, pEDROOMMemory->poolMarkCDBurst)
, EDROOMPoolCDDataBurst ( 10, pEDROOMMemory->poolCDDataBurst, pEDROOMMemory->poolMarkCDDataBurst)
{

}

// EDROOMBehaviour**********************************************

void CASgiDriver::EDROOMTopState::EDROOMBehaviour(){

	TEDROOMTransId edroomCurrentTrans;

	edroomCurrentTrans = EDROOMIllegada();

	do{

		switch(edroomCurrentTrans.localId){

			case(Init):
						FInit();
			edroomNextState = Listening;
			break;
			case(SendSignal):
						FSendBurstToGround();

			EDROOMcomponent.EDROOMTraceStateEntry();

			if( VMessageCompleted ){
				FBuildUpBurst();
				edroomCurrentTrans.localId = SendSignal_MessageReceived;
				edroomNextState = Listening;
			}
			else{
				FNotAnswer();
				edroomCurrentTrans.localId = SendSignal_NotAnswer;
				edroomNextState = Listening;
			}
			EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);
			break;
			case(SendData):
						FSendDataBurstToGround();

			EDROOMcomponent.EDROOMTraceStateEntry();

			if( VMessageCompleted ){
				FBuildUpBurst();
				edroomCurrentTrans.localId = SendData_MessageReceived;
				edroomNextState = Listening;
			}
			else{
				FNotAnswer();
				edroomCurrentTrans.localId = SendData_NotAnswer;
				edroomNextState = Listening;
			}
			EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);
			break;
		}

		EDROOMcomponent.EDROOMTraceStateEntry();

		EDROOMcomponent.EDROOMTraceStateEntry();

		switch(edroomNextState){

			case(I):
						edroomCurrentTrans=EDROOMIllegada();
			break;

			case(Listening):
						edroomCurrentTrans=EDROOMListeningllegada();
			break;

		}

		EDROOMcomponent.EDROOMTraceStateExit();

		edroomCurrentState=edroomNextState;

	}while(Msg->signal != EDROOMSignalDestroy);

}



// Inicio**********************************************

void CASgiDriver::EDROOMTopState::EDROOMInicio(){

	edroomCurrentState=I;

}



//	 ***********************************************************************

//	 llegada SubEstado I

//	 ***********************************************************************



TEDROOMTransId CASgiDriver::EDROOMTopState::EDROOMIllegada(){

	TEDROOMTransId edroomCurrentTrans;

	edroomCurrentTrans.localId = Init;
	edroomCurrentTrans.distanceToContext = 0;
	EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, 0);

	return(edroomCurrentTrans);

}



// ***********************************************************************

// llegada SubEstado Hoja Listening

// ***********************************************************************



TEDROOMTransId CASgiDriver::EDROOMTopState::EDROOMListeningllegada(){

	TEDROOMTransId edroomCurrentTrans;

	int edroomValidMsg=false;

	do{

		EDROOMNuevoMens ();

		switch(Msg->signal){

			case (STxBurst): 

						 if ( *Msg->GetPInterface() == SGIGround) {

							 edroomCurrentTrans.localId = SendSignal;
							 edroomCurrentTrans.distanceToContext = 0 ;
							 edroomValidMsg=true;
						 }

			break;

			case (STxDataBurst): 

						 if ( *Msg->GetPInterface() == SGIGround) {

							 edroomCurrentTrans.localId = SendData;
							 edroomCurrentTrans.distanceToContext = 0 ;
							 edroomValidMsg=true;
						 }

			break;

		};

		if (!edroomValidMsg) edroomValidMsg = EDROOMSearchContextTrans(edroomCurrentTrans);

	} while (!edroomValidMsg);

	EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);

	return(edroomCurrentTrans);

}



